# -*- coding: utf-8 -*-

#   This file is part of emesene.
#
#    Emesene is free software; you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation; either version 2 of the License, or
#    (at your option) any later version.
#
#    emesene is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with emesene; if not, write to the Free Software
#    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA

##   [DEV INSTRUCTIONS]
##   -> Plugin's aim is to let user create some emesene's macros;
##   -> A macro should be a list of actions represented
##      in the form of tuple ( type , value )
##      i.e. ( sendfile , filename)
##      Two way to implement it:
##      1) Parsing the whole list and call the right method associated to <type>
##         with <value> args
##      2) Define the tuple with as a callback <type> and as args <value>
##   -> I couldn't develop some things in UI (you can find the "tag" #TO-DO <description>
##
##   [CLASSES REFERENCE]
##
##   -> "MacrosMainDialog": is the dialog that will pop-up when you'll
##                          click on "config" plugin's button. Composed by:
##       -> "MacrosTreeView": to represent macros to user. NEEDS BINDING WITH DATA
##       -> "MacrosManagePanel": to let user manage macros
##
##   If you click on ADD or EDIT button in "MacrosMainDialog" you'll be prompted
##   the next dialog:
##   -> "MacrosCreateDialog": this dialog permits user to create a list of actions
##                            it's composed by:
##       -> "ActionsTreeView": to represent the list of actions to user NEEDS BINDING
##       -> "MacrosEditFrame": to let user choose and customize an action
##                             Personal image && Status box should be implemented
##
##   -> "MacroManager": is the manager that contains all informations and
##                      should be updated to introduce:
##                      add_macro()
##                      get_macro()
##                      set_macro()
##                      this object will be passed as argument to ALL classes
##                      in order to be updated/accessed to all these classes.
VERSION = 0.1

import gtk
import re
import emesenelib.common
import Plugin
import Widgets

class MainClass(Plugin.Plugin):
    '''
    Main class of the plugin.
    '''

    def __init__(self, controller, msn):
        '''Constructor'''

        Plugin.Plugin.__init__(self, controller, msn)
        self.description = 'Build your own emesene MACRO!'
        self.authors = {'Orfeo Ciano' : 'orfeo18 @ gmail com' , 'BoySka' : 'boyska @ gmail com' }
        self.website = 'http://code.google.com/p/emesene-plugins/'
        self.displayName = 'Macros'
        self.name = 'Macros'
        self.config = controller.config
        self.config.readPluginConfig(self.name)
        self.enabled = False

    def start(self):
        self.add_button()
        self.enabled = True

    def stop(self):
        self.remove_button()
        self.enabled = False

    def check(self):
        return (True, 'Ok')

    def configure(self):
        self.start_config_dialog()
        return True
    
    def add_button(self):

        self.macroButton = gtk.Button('M')
        self.controller.mainWindow.userPanel.vbox2.pack_start(self.macroButton,False,False)
        self.controller.mainWindow.userPanel.vbox2.show_all()
        mainDialog = MacrosMainDialog(self.controller)
        self.macroButton.connect('clicked',self.start_config_dialog)
        
    def remove_button(self):
        self.macroButton.destroy()
    
    #That def line is right with args=None?
    def start_config_dialog(self,args=None):
        MacrosMainDialog(self.controller).run()


class MacrosMainDialog(gtk.Dialog):
    '''
    Dialog that contains:
    -> MacrosTreeView
    ->MacrosManagePanel
    '''

    def __init__(self,controller):
        '''Constructor'''
        
        gtk.Dialog.__init__(self , _('Macros Manager'), None, \
            gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, \
            (gtk.STOCK_OK, gtk.RESPONSE_ACCEPT, \
            gtk.STOCK_CANCEL, gtk.RESPONSE_CLOSE))

        self.set_position(gtk.WIN_POS_CENTER_ON_PARENT)
        self.set_resizable(False)
        self.set_border_width(12)
        self.set_has_separator(False)
        #let's make a treeview
        
        self.controller=controller
        
        self.treeview = MacrosTreeView()
        viewport = gtk.Viewport()
        viewport.set_size_request(-1, 150)
        viewport.set_shadow_type(gtk.SHADOW_IN)
        viewport.add(self.treeview)
                
        #let's make a cool panel
        self.managerPanel = MacrosManagePanel(self.controller)
        self.vbox.set_spacing(5)
        
        self.vbox.pack_start(viewport)
        self.vbox.pack_start(self.managerPanel,False,False)
                
        self.vbox.show_all()
    
    def run(self):
        '''Method that manage the open and close of the dialog.'''
        response = gtk.Dialog.run(self)
        self.destroy()
        

class MacrosTreeView(gtk.TreeView):
    '''
    Class for showing macros data in main Panel to user.
    '''

    def __init__(self):
        '''Constructor'''
        
        self.liststore = gtk.ListStore(str, str, bool, str)

        gtk.TreeView.__init__(self, self.liststore)

        # Cells
        cell0 = gtk.CellRendererText()
        cell1 = gtk.CellRendererText()
        cell2 = gtk.CellRendererText()
        cell3 = gtk.CellRendererText()
        cell4 = gtk.CellRendererText()
        cell5 = gtk.CellRendererText()
        cell6 = gtk.CellRendererText()

        cell1.set_property('editable', False)
        #cell1.connect('edited', self.onEdited, self.liststore, 1)
        cell2.set_property('editable', False)
        #cell2.connect('toggled', self.onToggled, self.liststore, 2)
        cell3.set_property('editable', False)
        #cell3.connect('edited', self.onEdited, self.liststore, 3)
        cell4.set_property('editable', False)
        #cell4.connect('edited', self.onEdited, self.liststore, 1)
        cell5.set_property('editable', False)
        #cell5.connect('toggled', self.onToggled, self.liststore, 2)
        cell6.set_property('editable', False)
        #cell6.connect('edited', self.onEdited, self.liststore, 3)

        # Columns
        col0 = gtk.TreeViewColumn(_('Macro Name'), cell0 , text=0)
        col1 = gtk.TreeViewColumn(_('Nickname'), cell1, text=1)
        col2 = gtk.TreeViewColumn(_('Personal Message'), cell2, text=2)
        col3 = gtk.TreeViewColumn(_('Amsg'), cell3, text=3)
        col4 = gtk.TreeViewColumn(_('Personal Image'), cell4 , text=4)
        col5 = gtk.TreeViewColumn(_('Nudge'), cell5, text=5)
        col6 = gtk.TreeViewColumn(_('Status'), cell6, text=6)
        
        self.append_column(col0)
        self.append_column(col1)
        self.append_column(col2)
        self.append_column(col3)
        self.append_column(col4)
        self.append_column(col5)
        self.append_column(col6)
        

class MacrosManagePanel(gtk.Frame):
    '''
    Class that defines a frame to put buttons to:
    -> Open MacrosCreateDialog (to create a new macro)
    -> Open MacrosCreateDialog (to edit a selected macro)
    -> Delete an existing macro    
    '''
    def __init__(self,controller):
        gtk.Frame.__init__(self,_('Manage Macros'))
        
        self.controller=controller
        
        self.set_label_align(0.5,0.5)
        self.set_border_width(1)
        #let's add some buttons with tooltip
        addButton = gtk.Button("Create",gtk.STOCK_ADD)
        addButton.set_tooltip_text("Create a new macro.")
        addButton.connect('clicked',self.openManagePanel)
        
        editButton = gtk.Button("Edit",gtk.STOCK_EDIT)
        editButton.set_tooltip_text("Edit selected macro.")
        editButton.connect('clicked',self.openManagePanel)
        
        removeButton = gtk.Button("Remove",gtk.STOCK_REMOVE)
        removeButton.set_tooltip_text("Remove selected macro.")
        #TO-DO CALLS MacroManager.removeMacro(macroName)
        #removeButton.connect('clicked',self.callback)
        
        vbox = gtk.VBox()
        vbox.set_border_width(15)
        vbox.pack_start(addButton)
        vbox.pack_start(editButton)
        vbox.pack_start(removeButton)
        
        self.add(vbox)
    
    def openManagePanel(self,data=None):
        if data == None:
            MacrosCreateDialog().run()
        else: 
            MacrosCreateDialog(data,self.controller).run()
            

class MacrosCreateDialog(gtk.Dialog):
    '''
    Dialog that contains:
    -> ActionsTreeView to see the list of actions associated to a macro
    -> MacrosEditFrame to select which action you want to add to the macro
    '''

    def __init__(self, controller, Macro=None):
        '''Constructor'''
        
        gtk.Dialog.__init__(self , _('Macros Editor'), None, \
            gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, \
            (gtk.STOCK_OK, gtk.RESPONSE_ACCEPT, \
            gtk.STOCK_CANCEL, gtk.RESPONSE_CLOSE))
                
        self.set_position(gtk.WIN_POS_CENTER_ON_PARENT)
        self.set_resizable(False)
        self.set_border_width(25)
        self.set_has_separator(False)
        self.actionCounter = 0
        
        self.controller = controller
        
        #Macro name
        self.mNameLabel = gtk.Label("Macro Name:")
        self.mNameEntry = gtk.Entry()
        
        treeviewBox = gtk.HBox()
        #TreeView
        self.treeview = ActionsTreeView()
        viewport = gtk.Viewport()
        viewport.set_size_request(300, 200)
        viewport.set_shadow_type(gtk.SHADOW_IN)
        viewport.add(self.treeview)
        
        #TreeView associated buttons
        buttonsBox = gtk.VBox()
        
        moveUpButton = gtk.Button(None,gtk.STOCK_GO_UP)
        removeButton = gtk.Button(None, gtk.STOCK_CANCEL)
        moveDownButton = gtk.Button(None,gtk.STOCK_GO_DOWN)
        
        buttonsBox.pack_start(moveUpButton)
        buttonsBox.pack_start(removeButton)
        buttonsBox.pack_start(moveDownButton)
        
        actionsBox= gtk.Table(6, 7)
        actionsBox.attach(viewport,0, 6, 0, 6)
        actionsBox.attach(buttonsBox,6, 7, 2, 3,gtk.FILL,gtk.EXPAND,0,0)
        self.macrosEditFrame = MacrosEditFrame(self.controller)
        
        addButton = gtk.Button("Add",gtk.STOCK_ADD)        
        addButton.connect('released', self.add_action )
        
        self.vbox.add(self.mNameLabel)
        self.vbox.add(self.mNameEntry)
        self.vbox.add(actionsBox)
        self.vbox.add(treeviewBox)
        self.vbox.add(self.macrosEditFrame)
        self.vbox.add(addButton)
        
        self.vbox.show_all() 
    
    def add_action(self,data=None):
        actionData=self.macrosEditFrame.get_action()
        self.currentAction = ( self.actionCounter , actionData[0] , actionData[1])
        self.treeview.liststore.append(self.currentAction)
        self.actionCounter= self.actionCounter+1
        self.macrosEditFrame.clear()
        
    def run(self):
        '''Method that manage the open and close of the dialog.'''
        response = gtk.Dialog.run(self)
        self.destroy()
        
class ActionsTreeView(gtk.TreeView):
    '''Class for rappresenting Actions data'''

    def __init__(self):
        '''Constructor'''
        
        self.liststore = gtk.ListStore(int,str, str)

        gtk.TreeView.__init__(self, self.liststore)

        # Cells
        cell0 = gtk.CellRendererText()
        cell1 = gtk.CellRendererText()
        cell2 = gtk.CellRendererText()

        # Columns
        col0 = gtk.TreeViewColumn(_('Action #'), cell0 , text=0)
        col1 = gtk.TreeViewColumn(_('Type'), cell1, text=1)
        col2 = gtk.TreeViewColumn(_('Value'), cell2, text=2)
        
        self.append_column(col0)
        self.append_column(col1)
        self.append_column(col2)


class MacrosEditFrame(gtk.Frame):
    '''Class that defines a frame to choose the action for the new macro'''
    def __init__(self,controller):
        gtk.Frame.__init__(self,_('Choose Your Actions'))
        self.controller=controller
        
        self.set_label_align(0.25,0.5)
        self.set_border_width(1)
        
        #Personal Name
        self.pNameCheck = gtk.RadioButton(None, "New Nickname:")
        self.pNameCheck.connect("toggled", self.refresh)
        self.pNameEntry = gtk.Entry()
                
        #Personal Message
        self.psmCheck = gtk.RadioButton(self.pNameCheck,"New Personal Message:")
        self.psmCheck.connect("toggled", self.refresh)
        self.psmEntry = gtk.Entry()
        self.psmEntry.set_sensitive(False)
        
        #amsg
        self.amsgCheck = gtk.RadioButton(self.pNameCheck,"Amsg:")
        self.amsgCheck.connect("toggled", self.refresh)
        self.amsgEntry = gtk.Entry()
        self.amsgEntry.set_sensitive(False)
        
        #Personal image
        self.pImgCheck = gtk.RadioButton(self.amsgCheck,"Change Personal Image:")
        self.pImgCheck.connect("toggled", self.refresh)
        self.pImg = Widgets.avatarHolder(cellDimention = 48)
        self.pImgEventBox = gtk.EventBox()
        self.pImgEventBox.set_events(gtk.gdk.BUTTON_PRESS_MASK)
        self.pImgEventBox.set_sensitive(False)
        #TO-DO CREATE A CALLBACK FOR IMGEVENTBOX
        #self.pImgEventBox.connect('button-press-event', self.avatarClicked)
        self.pImgEventBox.add(self.pImg)
        
        #Nudge
        self.nudgeCheck = gtk.RadioButton(self.pImgCheck,"Nudge:")
        self.nudgeCheck.connect("toggled", self.refresh)
        
        #Status
        self.statusCheck = gtk.RadioButton(self.nudgeCheck,"Change Status:")
        self.statusCheck.connect("toggled", self.refresh)
        #TO-DO: GET STATUS ITEMS
        #self.statusStore = gtk.ListStore(str,str)
        #
        #for i in self.controller.status_ordered[0].index(i):
        #    self.list_store.append([i, self.controller.status_ordered[i][i]])
        
        #Wait for x seconds before making next action
        self.sleepCheck = gtk.RadioButton(self.nudgeCheck,"Delay (in Milliseconds):")
        self.sleepCheck.connect("toggled", self.refresh)
        adj = gtk.Adjustment(0.0, 0.0, 120000.0, 100.0, 5.0, 0.0)
        self.sleepSpin = gtk.SpinButton(adj,0,0)
        self.sleepSpin.set_sensitive(False)
        self.sleepSpin.set_wrap(True)
        
        
        #pack everything
        tableBox=gtk.Table(2, 7)
        tableBox.attach(self.pNameCheck, 0, 1, 0, 1)
        tableBox.attach(self.pNameEntry, 1, 2, 0, 1)
        tableBox.attach(self.psmCheck,0, 1, 1, 2)
        tableBox.attach(self.psmEntry,1, 2, 1, 2)
        tableBox.attach(self.amsgCheck,0, 1, 2, 3)
        tableBox.attach(self.amsgEntry,1, 2, 2, 3)
        tableBox.attach(self.pImgCheck,0, 1, 3, 4)
        tableBox.attach(self.pImgEventBox,1, 2, 3, 4)
        tableBox.attach(self.nudgeCheck,0, 1, 4, 5)
        tableBox.attach(self.statusCheck,0, 1, 5, 6)
        #tableBox.attach(self.statusStore,1, 2, 5, 6)
        tableBox.attach(self.sleepCheck,0, 1, 6, 7)
        tableBox.attach(self.sleepSpin,1, 2, 6, 7)
        
        vbox=gtk.VBox()
        vbox.set_border_width(15)
        vbox.pack_start(tableBox)
        vbox.show_all()
        
        self.add(vbox)
    
    def get_action(self,data=None):
        '''This method returns a tuple <type> , <value>'''
        
        if self.pNameCheck.get_active():
            return ('name' , self.pNameEntry.get_text())
        elif self.psmCheck.get_active():
            return ('psm' , self.psmEntry.get_text())
        elif self.amsgCheck.get_active():
            return ('amsg' , self.amsgEntry.get_text())
        elif self.pImgCheck.get_active():
            #TO-DO HOW TO MAKE IT? we need the new personal image
            print("TO-DO: New Personal Image")
        elif self.nudgeCheck.get_active():
            return( 'nudge' , '' )
        elif self.statusCheck.get_active():
            #TO-DO Get the new status
            print("TO-DO: New Status")
        elif self.sleepCheck.get_active():
            return( 'sleep' , self.sleepSpin.get_value_as_int() )
    
    def refresh(self, data=None):
        '''enables the right entry/widget associated with radio button'''
        if self.pNameCheck.get_active():
            self.pNameEntry.set_sensitive(True)
            self.psmEntry.set_sensitive(False)
            self.amsgEntry.set_sensitive(False)
            self.pImgEventBox.set_sensitive(False)
            #self.statusList.set_sensitive(False)
            self.sleepSpin.set_sensitive(False)
        
        elif self.psmCheck.get_active():
            self.pNameEntry.set_sensitive(False)
            self.psmEntry.set_sensitive(True)
            self.amsgEntry.set_sensitive(False)
            self.pImgEventBox.set_sensitive(False)
            #self.statusList.set_sensitive(False)
            self.sleepSpin.set_sensitive(False)
        
        elif self.amsgCheck.get_active():
            self.pNameEntry.set_sensitive(False)
            self.psmEntry.set_sensitive(False)
            self.amsgEntry.set_sensitive(True)
            self.pImgEventBox.set_sensitive(False)
            #self.statusList.set_sensitive(False)
            self.sleepSpin.set_sensitive(False)
        
        elif self.pImgCheck.get_active():
            self.pNameEntry.set_sensitive(False)
            self.psmEntry.set_sensitive(False)
            self.amsgEntry.set_sensitive(False)
            self.pImgEventBox.set_sensitive(True)
            #self.statusList.set_sensitive(False)
            self.sleepSpin.set_sensitive(False)
        
        elif self.nudgeCheck.get_active():
            self.pNameEntry.set_sensitive(False)
            self.psmEntry.set_sensitive(False)
            self.amsgEntry.set_sensitive(False)
            self.pImgEventBox.set_sensitive(False)
            #self.statusList.set_sensitive(False)
            self.sleepSpin.set_sensitive(False)
        
        elif self.statusCheck.get_active():
            self.pNameEntry.set_sensitive(False)
            self.psmEntry.set_sensitive(False)
            self.amsgEntry.set_sensitive(False)
            self.pImgEventBox.set_sensitive(False)
            #self.statusList.set_sensitive(True)
            self.sleepSpin.set_sensitive(False)
        
        elif self.sleepCheck.get_active():
            self.pNameEntry.set_sensitive(False)
            self.psmEntry.set_sensitive(False)
            self.amsgEntry.set_sensitive(False)
            self.pImgEventBox.set_sensitive(False)
            #self.statusList.set_sensitive(False)
            self.sleepSpin.set_sensitive(True)
    
    def clear(self):
        '''empties all fields'''
        self.pNameEntry.set_text('')
        self.psmEntry.set_text('')
        self.amsgEntry.set_text('')
        self.sleepSpin.set_value(0)
    
    def run(self):
        '''Method that manage the open and close of the dialog.'''
        response = gtk.Dialog.run(self)
        self.destroy()

class MacroManager:
    
    def __init__(self, dictionary ):
        self.dictionary = dictionary
    
    def get_macro(self, macroName):
        if macroName in self.dictionary:
            return self.dictionary[macroName]
            
    def add_macro(self, actionlist):
        self.dictionary[actionlist[0]] = actionlist[1:]
    
    def remove_macro(self,macroName):
        self.dictionary.pop(macroName)
    
    def editAction(self, macroName, actionNumber, newaction):
        (self.dictionary[macroName])[actionNumber] = newaction

    def run_macro(self, macro):
        for id, param in macro:
            if id == 'sendfile':
                pass
            if id == 'nudge':
                pass
            if id == 'set_nick':
                pass
